<template>
  <div class="process-scheduling">
        
        <Button type="primary" ghost @click="addProcess">添加进程</Button>

        <Table :columns="columns1" :data="data1"></Table>
        <Tabs value="FCFS" @on-click="clickTabs">
            <TabPane label="先来先服务" name="FCFS">
              <div id="chart-container1" :style="{ width: '100%', height: '700px' }" ref="chartContainer1"></div>
            </TabPane>
            <TabPane label="短作业优先" name="SJF">
              <div id="chart-container2" :style="{ width: '100%', height: '700px' }" ref="chartContainer2"></div>
            </TabPane>
        </Tabs>
        

  </div>
</template>

<script>
import {echarts} from '../echarts';
export default {
  data() {
    const _this = this
    return {
      columns1: [
          {
              title: '序号',
              key: 'index'
          },
          {
              title: '进程名',
              key: 'name'
          },
          {
              title: '到达时间',
              key: 'arrival-time',
              render(h, params) {
                return h('div', [
                  h('InputNumber', {
                    props: {
                      value: params.row['arrival-time']
                    },
                    on: {
                      input(value) {
                        params.row['arrival-time'] = value
                        _this.data1[params.index]['arrival-time'] = value
                        if(_this.isFCFS) {
                          _this.renderChartWithFCFS()
                        } else {
                          _this.renderChartWithSJF()
                        }
                      }
                    }
                  })
                ])
              }
          },
          {
              title: '服务时间',
              key: 'service-time',
              render(h, params) {
                return h('div', [
                  h('InputNumber', {
                    props: {
                      value: params.row['service-time']
                    },
                    on: {
                      input(value) {
                        params.row['service-time'] = value
                        _this.data1[params.index]['service-time'] = value
                        if(_this.isFCFS) {
                          _this.renderChartWithFCFS()
                        } else {
                          _this.renderChartWithSJF()
                        }
                      }
                    }
                  })
                ])
              }
          },
          {
            title: '完成时间',
            key: 'end-time'
          },
          {
            title: '周转时间',
            key: 'turnaround-time'
          },
          {
            title: '带权周转时间',
            key: 'float-Wi'
          },
          {
            title: '操作',
            key: 'handle',
            render(h, params) {
              return h('div', [
                h('Button', {
                  on: {
                    click() {
                      _this.data1.splice(params.index, 1)
                      if(_this.isFCFS) {
                        _this.renderChartWithFCFS()
                      } else {
                        _this.renderChartWithSJF()
                      }
                    }
                  },
                  props: {
                    type: 'error',
                    ghost: true
                  }
                }, '删除')
              ])
            }
          }
      ],
      data1: [
          {
              index: 1,
              name: '进程1',
              'arrival-time': 0,
              'service-time': 2,
          },
          {
              index: 2,
              name: '进程2',
              'arrival-time': 3,
              'service-time': 3
          },
          {
              index: 3,
              name: '进程3',
              'arrival-time': 4,
              'service-time': 2
          }
      ],
      index: 3,
      /**
       * @Descripttion: 当前显示的是否是FCFS
       */
      isFCFS: true
    }
  },
  methods: {
      /**
       * @Descripttion 添加进程函数
       *                向进程数组末尾添加新的进程，添加完成后，重新调用渲染canvas函数
       * @param {type} 
       * @return void
       */
      addProcess() {
        this.index++
        this.data1.push({
          index: this.index,
          name: '进程' + this.index,
          'arrival-time': this.data1[this.data1.length - 1]['arrival-time'] + 1,
          'service-time': 2
        })
        if(this.isFCFS) {
          this.renderChartWithFCFS()
        } else {
          this.renderChartWithSJF()
        }
      },
      /**
       * @Descripttion 切换不同的tabs时调用（切换FCFS和SJF）
       * @param {type} 
       * @return
       */
      clickTabs(name) {
        switch (name) {
          case 'FCFS':
            this.isFCFS = true
            this.renderChartWithFCFS()
            break;
          case 'SJF':
            this.isFCFS = false
            this.renderChartWithSJF()
            break;
        }
      },
      /**
       * @Descripttion FCFS的主要算法实现，同时把数据渲染到canvas中
       *                1. 进程排序（先来的排前面，同时到达的服务时间短排前面）
       *                2. 渲染数据
       * @param {type} 
       * @return
       */      
      renderChartWithFCFS() {
        // 进程队列
        let queueFCFS = []
        // 进程名
        const queueName = []
        // 到达时间
        const queueArrivalTime = []
        // 服务时间
        const queueServiceTime = []
        // 辅助填充
        const padding = []
        // 当前时间
        let local = 0

        queueFCFS = [...this.data1]
        queueFCFS.sort((a, b) => {
          if (a['arrival-time'] === b['arrival-time']) {
                return a['service-time'] - b['service-time']
            } else {
                return a['arrival-time'] - b['arrival-time']
            }
        })

        queueFCFS.forEach((item, index) => {
          if(local < item['arrival-time']) {
            padding.push(item['arrival-time'])
            local = item['arrival-time']
          } else {
            padding.push(local)
          }
          this.data1.some((v, i) => {
            if(item['index'] === v['index']) {
              this.$set(this.data1[i], 'end-time', local + item['service-time'])
              this.$set(this.data1[i], 'turnaround-time', local +item['service-time'] - item['arrival-time'])
              this.$set(this.data1[i], 'float-Wi', (local +item['service-time'] - item['arrival-time']) / item['service-time'])
            }
          })
          
          queueName.push(item.name)
          if(index === 0) {
            local = item['arrival-time'] + item['service-time']
          } else {
            local += item['service-time']
          }
          
          queueArrivalTime.push(item['arrival-time'])
          queueServiceTime.push(item['service-time'])
        })
        // 先来先服务容器
        let myChart1 = echarts.init(this.$refs.chartContainer1)

        // 绘制图表
        myChart1.setOption({
            tooltip : {
                trigger: 'axis',
                axisPointer : {            // 坐标轴指示器，坐标轴触发有效
                    type : 'shadow'        // 默认为直线，可选为：'line' | 'shadow'
                },
                formatter: function (params) {
                    var tar = params[1];
                    return tar.name + '<br/>' + tar.seriesName + ' : ' + tar.value;
                }
            },
            grid: {
                left: '0',
                right: '5%',
                bottom: '10%',
                top: '5%',
                containLabel: true
            },
            yAxis: {
                type : 'category',
                splitLine: {show:false},
                data : queueName,
                name: '进程名',
                nameLocation: 'end',
                inverse: true,
                axisLabel: {
                  color: '#19be6b'
                }
            },
            xAxis: {
                type : 'value',
                position: 'top',
                name: '时间',
                min: 0,
                max: 'dataMax',
                interval: 1,
                axisLabel: {
                  formatter: params => {
                    let index
                    if(queueArrivalTime.some((item, currentIndex) => {
                      if(params === item) {
                        index = currentIndex
                        return true
                      }
                    })) {
                      let name = queueFCFS[index].name.split('').join('\n')
                      return name + '\n到\n达\n时\n间\n\n' + params
                    } else {
                      return params
                    }
                  },
                  color: '#19be6b'
                }
            },
            series: [
                {
                    name: '辅助',
                    type: 'bar',
                    stack:  '总量',
                    itemStyle: {
                        normal: {
                            barBorderColor: 'rgba(0,0,0,0)',
                            color: 'rgba(0,0,0,0)'
                        },
                        emphasis: {
                            barBorderColor: 'rgba(0,0,0,0)',
                            color: 'rgba(0,0,0,0)'
                        }
                    },
                    data: padding

                },
                {
                    name: '服务时间',
                    type: 'bar',
                    stack: '总量',
                    label: {
                        show: true,
                        formatter: '{b}\n\n{a} : {c}'
                    },
                    data: queueServiceTime
                }
            ],
            color: ['#2d8cf0', '#c23531','#2f4554']
        });
      },

      /**
       * @Descripttion SJF的主要算法实现，同时把数据渲染到canvas中
       *                1. 进程排序（先来的排前面，同时到达的服务时间短排前面）
       *                2. 对排好序的队列进行遍历，把队首元素放到就绪队列queueReady中，计算当前时间local，
       *                    遍历到第二个及以后的进程时，判断当前时间和当前进程的到达时间，如果在当前时间以前，
       *                    进程已经到达的，把它们放到等待队列中，等待进一步的处理
       *                3. 如果当前时间下，已经没有进程到达了，则处理等待序列中的进程。
       *                    先按照服务时间长短排序，排完序之后计算，放入就绪队列，计算当前时间。
       *                    继续循环判断当前时间和当前进程到达时间的大小，重复2，3步骤，直到循环到最后一个进程。
       *                4. 渲染数据。
       * @param {type} queueFCFS 进程队列
       * @return
       */
      renderChartWithSJF() {
        // 进程队列
        let queueSJF = []
        // 等待队列
        let queueWait = []
        // 就绪队列
        let queueReady = []
        // 当前时间
        let local = 0
        // 进程名
        const queueName = []
        // 到达时间
        const queueArrivalTime = []
        // 服务时间
        const queueServiceTime = []
        // 辅助填充
        const padding = []
        
        queueSJF = [...this.data1]
        queueSJF.sort((a, b) => {
          if (a['arrival-time'] === b['arrival-time']) {
                return a['service-time'] - b['service-time']
            } else {
                return a['arrival-time'] - b['arrival-time']
            }
        })
        queueSJF.forEach((item, index, thisArg) => {

          if(index === 0) {
            queueReady.push(item)
            local = item['arrival-time'] + item['service-time']
          } else if(item['arrival-time'] <= local) {
            queueWait.push(item)
          } else {
            queueWait.sort((a, b) => {
              return a['service-time'] - b['service-time']
            })
            local += queueWait.reduce((accumulator, currentValue) => {
              return accumulator + currentValue['service-time']
            }, 0)
            queueReady.push(...queueWait)
            queueWait.splice(0, queueWait.length, item)
          }
          if(index === thisArg.length - 1) {
            queueWait.sort((a, b) => {
              return a['service-time'] - b['service-time']
            })
            queueReady.push(...queueWait)
          }
        })

        local = 0
        queueReady.forEach((item, index) => {

          if(local < item['arrival-time']) {
            padding.push(item['arrival-time'])
            local = item['arrival-time']
          } else {
            padding.push(local)
          }
          this.data1.some((v, i) => {
            if(item['index'] === v['index']) {
              this.$set(this.data1[i], 'end-time', local + item['service-time'])
              this.$set(this.data1[i], 'turnaround-time', local +item['service-time'] - item['arrival-time'])
              this.$set(this.data1[i], 'float-Wi', (local +item['service-time'] - item['arrival-time']) / item['service-time'])
            }
          })
          queueName.push(item.name)

          if(index === 0) {
            local += item['arrival-time'] + item['service-time']
          } else {
            local += item['service-time']
          }
          
          queueServiceTime.push(item['service-time'])
          queueArrivalTime.push(item['arrival-time'])
          
        })
        
        
        
        // 最短作业优先容器
        let myChart1 = echarts.init(this.$refs.chartContainer2)

        // 绘制图表
        myChart1.setOption({
            tooltip : {
                trigger: 'axis',
                axisPointer : {            // 坐标轴指示器，坐标轴触发有效
                    type : 'shadow'        // 默认为直线，可选为：'line' | 'shadow'
                },
                formatter: function (params) {
                    var tar = params[1];
                    return tar.name + '<br/>' + tar.seriesName + ' : ' + tar.value;
                }
            },
            grid: {
                left: '0',
                right: '5%',
                bottom: '10%',
                top: '5%',
                containLabel: true
            },
            yAxis: {
                type : 'category',
                splitLine: {show:false},
                data : queueName,
                name: '进程名',
                nameLocation: 'end',
                inverse: true,
                axisLabel: {
                  color: '#19be6b'
                }
            },
            xAxis: {
                type : 'value',
                position: 'top',
                name: '时间',
                min: 0,
                max: 'dataMax',
                interval: 1,
                axisLabel: {
                  formatter: params => {
                    let index
                    if(queueArrivalTime.some((item, currentIndex) => {
                      if(params === item) {
                        index = currentIndex
                        return true
                      }
                    })) {
                      let name = queueReady[index].name.split('').join('\n')
                      return name + '\n到\n达\n时\n间\n\n' + params
                    } else {
                      return params
                    }
                  },
                  color: '#19be6b'
                }
            },
            series: [
                {
                    name: '辅助',
                    type: 'bar',
                    stack:  '总量',
                    itemStyle: {
                        normal: {
                            barBorderColor: 'rgba(0,0,0,0)',
                            color: 'rgba(0,0,0,0)'
                        },
                        emphasis: {
                            barBorderColor: 'rgba(0,0,0,0)',
                            color: 'rgba(0,0,0,0)'
                        }
                    },
                    data: padding

                },
                {
                    name: '服务时间',
                    type: 'bar',
                    stack: '总量',
                    label: {
                        show: true,
                        formatter: '{b}\n\n{a} : {c}'
                    },
                    data: queueServiceTime
                }
            ],
            color: ['#2d8cf0', '#c23531','#2f4554']
        });
      }
  },
  mounted() {
    if(this.isFCFS) {
      this.renderChartWithFCFS()
    } else {
      this.renderChartWithSJF()
    }
  },
}
</script>

<style scope lang="less">
  .process-scheduling {
    .ivu-btn {
      margin-top: 20px;
      margin-bottom: 20px;
    }
    .ivu-tabs {
      margin-top: 30px;
    }
  }
</style>